﻿using Essensoft.AspNetCore.Payment.Alipay;
using Essensoft.AspNetCore.Payment.Alipay.Domain;
using Essensoft.AspNetCore.Payment.Alipay.Notify;
using Essensoft.AspNetCore.Payment.Alipay.Request;
using Essensoft.AspNetCore.Payment.Alipay.Utility;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NewRetail.Application.Components.Dashboard.Model;
using NewRetail.Application.Components.Platform;
using NewRetail.Application.Components.Platform.Entity;
using NewRetail.Application.Components.StoreValueCard.Entity;
using NewRetail.Application.Components.WeChat.Configurations;
using NewRetail.Application.Components.WeChat.Services.HttpClients;
using NewRetail.Application.Components.WechatOrAlipayPayment.Entity;
using NewRetail.Application.Components.WechatOrAlipayPayment.Model;
using NewRetail.Application.Core.Entity;
using NewRetail.Application.Utility;
using Newtonsoft.Json.Linq;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Uow;

namespace NewRetail.Application.Components.WechatOrAlipayPayment.Services
{
    #region 接口
    /// <summary>
    /// 接口
    /// </summary>
    public interface IWeChatOrAlipayPaymentService : IApplicationService
    {
        #region 支付宝相关
        /// <summary>
        /// 支付宝手机网页支付
        /// </summary>
        /// <param name="inputData"></param>
        /// <returns></returns>
        Task<(PayResultShowDto, int, string)> WapAlipayPay(AlipayTradeWapPayViewDto inputData);

        /// <summary>
        /// 支付宝支付回调通知
        /// </summary>
        /// <param name="requestData"></param>
        /// <returns></returns>
        Task<string> AsynAlipayNotify(HttpRequest requestData);
        /// <summary>
        /// 支付结果查询
        /// </summary>
        /// <param name="queryDto"></param>
        /// <returns></returns>
        Task<string> AlipayPayTradeQueryAsync(AlipayTradeQueryDto queryDto);

        #endregion

        #region 微信相关
        /// <summary>
        /// 微信支付JSAPI下单
        /// </summary>
        /// <param name="requestModel"></param>
        /// <returns></returns>
        Task<(string, string, WeChatPayTransactionJsapiShowDto)> CreatePayTransactionJsapi(CreateOrderByJsapiRequestDto requestModel);
        /// <summary>
        /// 商户订单号查询
        /// </summary>
        /// <param name="requestModel"></param>
        /// <returns></returns>
        Task<(string, GetPayTransactionByOutTradeNumberResponse)> GetPayTransactionByOutTradeNumberAsync(PayTransactionByOutTradeNumberRequestDto requestModel);
        /// <summary>
        /// 商户关闭订单(直接调微信接口关闭订单)
        /// </summary>
        /// <param name="requestModel"></param>
        /// <returns></returns>
        Task<(string, ClosePayTransactionResponse)> ClosePayTransactionByOutTradeNumberAsync(PayTransactionByOutTradeNumberRequestDto requestModel);
        /// <summary>
        /// 微信支付回调通知
        /// </summary>
        /// <param name="contentData"></param>
        /// <returns></returns>
        Task<string> AsynWechatNotify(string contentData);
        #endregion
    }
    #endregion

    #region 实现
    /// <summary>
    /// 实现微信或支付宝支付
    /// </summary>
    public class WeChatOrAlipayPaymentService : ApplicationService, IWeChatOrAlipayPaymentService
    {
        #region Field
        private readonly ILogger _logger;
        private readonly IAlipayClient _client;
        private readonly IAlipayNotifyClient _notifyClient;
        private readonly IOptions<AlipayOptions> _optionsAccessor;
        private readonly WxpayOptions _wechatPayOptions;
        private readonly IWechatTenpayHttpClientFactory _wechatTenpayHttpClientFactory;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        protected IEntityHelper _entityHelper => this.LazyServiceProvider.LazyGetRequiredService<IEntityHelper>();
        protected INoGeneratorService _noGeneratorService => this.LazyServiceProvider.LazyGetRequiredService<INoGeneratorService>();
        private readonly IRepository<CardRechargeRecordEntity> _cardRechargeRecordRepository;
        private readonly IRepository<PosPayResultFlow> _posPayResultFlowRepository;
        #endregion

        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="optionsAccessor"></param>
        /// <param name="client"></param>
        /// <param name="logger"></param>
        public WeChatOrAlipayPaymentService(IOptions<AlipayOptions> optionsAccessor, IAlipayClient client, IOptions<WxpayOptions> wechatPayOptions,
            IWechatTenpayHttpClientFactory wechatTenpayHttpClientFactory, IUnitOfWorkManager unitOfWorkManager,
            IRepository<CardRechargeRecordEntity> cardRechargeRecordRepository, IAlipayNotifyClient notifyClient,
            IRepository<PosPayResultFlow> posPayResultFlowRepository, ILogger<WeChatOrAlipayPaymentService> logger)
        {
            _client = client;
            _optionsAccessor = optionsAccessor;
            _wechatPayOptions = wechatPayOptions.Value;
            _wechatTenpayHttpClientFactory = wechatTenpayHttpClientFactory;
            _unitOfWorkManager = unitOfWorkManager;
            _cardRechargeRecordRepository = cardRechargeRecordRepository;
            _notifyClient = notifyClient;
            _posPayResultFlowRepository = posPayResultFlowRepository;
            _logger = logger;
        }
        #endregion

        #region method        

        #region 支付宝支付相关

        #region 支付宝手机网页支付
        /// <summary>
        /// 支付宝手机网页支付
        /// </summary>
        /// <param name="inputData"></param>
        /// <returns></returns>
        public async Task<(PayResultShowDto, int, string)> WapAlipayPay(AlipayTradeWapPayViewDto inputData)
        {
            AlipayTradeWapPayModel model = new AlipayTradeWapPayModel
            {
                Body = "手机网站支付描述信息",
                Subject = "手机网站支付测试",
                TotalAmount = "0.01",
                OutTradeNo = UtilsHelper.getFormatedDateString("eastern standard time").Trim(),//存在本地的订单编号
                ProductCode = "QUICK_WAP_WAY",//请求类型
                QuitUrl = "http://www.hj0819.top:8081/#/order/1",//用户取消支付后的跳转地址
            };
            var req = new AlipayTradeWapPayRequest();
            req.SetBizModel(model);
            //支付宝服务器主动通知商户服务器里指定的页面http/https路径。 
            req.SetNotifyUrl("http://cldvip.nat300.top/api/new-retail/wechat-alipay-payment/alipay-notify");
            //可实现支付成功后跳转到商家页面的功能，而且跳转后的return_url页面的地址栏中会返回同步通知参数。
            req.SetReturnUrl("http://www.hj0819.top:8081/#/aliPayIsok");

            var response = await _client.PageExecuteAsync(req, _optionsAccessor.Value);
            if (response.IsError)
            {
                //错误时
                return (null, 203, "支付宝对接错误：" + response.Msg);
            }
            var resultObj = new PayResultShowDto()
            {
                PayResultData = response.Body
            };

            return (resultObj, 201, "支付宝对接成功");
        }
        #endregion

        #region 支付宝支付回调通知
        /// <summary>
        /// 支付宝支付回调通知
        /// </summary>
        /// <param name="requestData"></param>
        /// <returns></returns>
        public async Task<string> AsynAlipayNotify(HttpRequest requestData)
        {
            try
            {
                var notify = await _notifyClient.ExecuteAsync<AlipayTradeAppPayNotify>(requestData, _optionsAccessor.Value);
                string strJson = Newtonsoft.Json.JsonConvert.SerializeObject(notify, Newtonsoft.Json.Formatting.Indented);
                _logger.LogInformation("Resp=" + strJson);
                var verifyRet = AlipaySignature.RSACheckContent(strJson, notify.Sign, _optionsAccessor.Value.AlipayPublicKey, _optionsAccessor.Value.SignType);
                decimal order_price = decimal.Parse(notify.BuyerPayAmount);
                string out_trade_no = notify.OutTradeNo; //商户订单
                string trade_status = notify.TradeStatus; // "支付状态"
                string trade_no = notify.TradeNo; // 支付宝交易号
                
                #region 支付后存库                        
                //var db = await _posPayResultFlowRepository.GetDbContextAsync();
                var posPayResultFlow = new PosPayResultFlow()
                {
                    flowNo = out_trade_no,
                    tradeNo = trade_no,
                    payAmount = order_price,
                    payWay = Enum.GetName(typeof(PayWayEnum), PayWayEnum.Z),
                    payTime = notify.GmtPayment.ObjToDate(),
                    tradeStatus = trade_status
                };
                _entityHelper.InitEntity(posPayResultFlow);
                await _posPayResultFlowRepository.InsertAsync(posPayResultFlow, autoSave: true);
                #endregion

                //if (notify.TradeStatus == "TRADE_SUCCESS")
                //{
                //    //这里写支付成功的业务逻辑
                //}
                //else
                //{
                //    //这里写支付失败的业务处理
                //}

            }
            catch (SystemException ex)
            {
                string json = Newtonsoft.Json.JsonConvert.SerializeObject(ex, Newtonsoft.Json.Formatting.Indented);
                _logger.LogError("Errors=" + json);
                return "error" + json;
            }
            return null;
        }
        #endregion

        #region 支付结果查询
        /// <summary>
        /// 支付结果查询
        /// </summary>
        /// <param name="queryDto"></param>
        /// <returns></returns>
        public async Task<string> AlipayPayTradeQueryAsync(AlipayTradeQueryDto queryDto)
        {
            var model = new AlipayTradeQueryModel
            {
                OutTradeNo = queryDto.OutTradeNo.Trim(),
                TradeNo = queryDto.TradeNo
            };

            var req = new AlipayTradeQueryRequest();
            req.SetBizModel(model);
            var response = await _client.ExecuteAsync(req, _optionsAccessor.Value);
            //转换为json
            JObject jos = UtilsHelper.DeserializeObject<JObject>(((AlipayResponse)response).Body);
            string aliPay = jos["alipay_trade_query_response"].ToString();
            JObject jo = UtilsHelper.DeserializeObject<JObject>(aliPay);
            string code = jo["code"].ToString();
            //解析信息
            if (code != "10000")
            {
                //一般错误为 交易不存在
            }
            //解析支付宝的交易流水
            string trade_no = jo["trade_no"].ToString();
            return null;
        }
        #endregion

        #endregion

        #region 微信支付相关

        #region 微信支付JSAPI下单
        /// <summary>
        /// 微信支付JSAPI下单
        /// </summary>
        /// <param name="requestModel"></param>
        /// <returns></returns>
        public async Task<(string, string, WeChatPayTransactionJsapiShowDto)> CreatePayTransactionJsapi(CreateOrderByJsapiRequestDto requestModel)
        {
            var appId = "";
            var merchantId = "";
            var errMsg = "";
            var result = "";
            var openId = requestModel.OpenId;
            var weChatPayTransactionJsapi = new WeChatPayTransactionJsapiShowDto();
            try
            {
                //appId为null则默认获取配置第一个
                if (string.IsNullOrEmpty(requestModel.AppId))
                    appId = _wechatPayOptions.Merchants?.FirstOrDefault().AppId;
                //商户号不指定，那么获取配置第一个
                if (string.IsNullOrEmpty(merchantId))
                    merchantId = _wechatPayOptions.Merchants?.FirstOrDefault().MerchantId;
                //创建一个http
                var client = _wechatTenpayHttpClientFactory.Create(merchantId);
                var outTradeNumber = requestModel.OutTradeNumber;// "WX_" + openId.Substring(openId.Length - 4) + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff");
                var rechargeAmount = requestModel.Amount;

                #region 先存订单
                //将订单存本地库                        
                var db = await _cardRechargeRecordRepository.GetDbContextAsync();
                var posMember = await db.Set<PosMember>().AsNoTracking().FirstOrDefaultAsync(x => x.openId == openId);
                //从库里获取记录
                var cardRechargeRecord = await db.Set<CardRechargeRecordEntity>().AsNoTracking().FirstOrDefaultAsync(x => x.outTradeNumber == outTradeNumber && x.openId == openId);
                if (cardRechargeRecord == null)
                {
                    var giftAmount = requestModel.GiftAmount;
                    //不存在则新增
                    cardRechargeRecord = new CardRechargeRecordEntity()
                    {
                        rechargeDate = DateTime.Now.ToString("yyyy-MM-dd"),
                        rechargeDateTime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),
                        outTradeNumber = outTradeNumber,
                        openId = openId,
                        memberNo = posMember != null ? posMember.No : "",
                        rechargeAmount = rechargeAmount,
                        giftAmount = giftAmount,
                        rechargeStatus = 2,
                        payWay = 1,
                        memberId = posMember != null ? posMember.Id : ""
                    };
                    _entityHelper.InitEntity(cardRechargeRecord);
                    await _cardRechargeRecordRepository.InsertAsync(cardRechargeRecord, autoSave: true);
                }
                #endregion

                var request = new CreatePayTransactionJsapiRequest()
                {
                    OutTradeNumber = outTradeNumber,
                    AppId = appId,
                    Description = requestModel?.Description,
                    ExpireTime = DateTimeOffset.Now.AddMinutes(30),
                    NotifyUrl = "http://127.0.0.1",
                    Amount = new CreatePayTransactionJsapiRequest.Types.Amount()
                    {
                        Total = rechargeAmount
                    },
                    Payer = new CreatePayTransactionJsapiRequest.Types.Payer()
                    {
                        OpenId = openId
                    }
                };
                var response = await client.ExecuteCreatePayTransactionJsapiAsync(request);
                if (!response.IsSuccessful())
                {
                    _logger.LogWarning(
                        "JSAPI 下单失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                        response.RawStatus, response.ErrorCode, response.ErrorMessage
                    );
                    errMsg = response.ErrorMessage;
                    return (result, errMsg, null);
                }
                else
                {
                    //下单成功则生成客户端JSAPI/小程序调起支付所需的参数
                    var resultParams = client.GenerateParametersForJsapiPayRequest(appId, response.PrepayId);
                    if (resultParams != null)
                    {
                        weChatPayTransactionJsapi.appId = resultParams["appId"];
                        weChatPayTransactionJsapi.nonceStr = resultParams["nonceStr"];
                        weChatPayTransactionJsapi.timestamp = resultParams["timeStamp"];
                        weChatPayTransactionJsapi.package = resultParams["package"];
                        weChatPayTransactionJsapi.signType = resultParams["signType"];
                        weChatPayTransactionJsapi.paySign = resultParams["paySign"];

                        result = response.PrepayId;

                        
                    }
                    else
                    {
                        errMsg = "获取返回的参数失败！";
                    }
                }
            }
            catch (Exception e)
            {
                _logger.LogError("下单异常：" + e.Message);
                errMsg = "下单失败!" + e.Message;
            }
            return (result, errMsg, weChatPayTransactionJsapi);
        }

        #endregion

        #region 商户订单号查询
        /// <summary>
        /// 商户订单号查询(直接调微信接口查询订单状态)
        /// </summary>
        /// <param name="requestModel"></param>
        /// <returns></returns>
        public async Task<(string, GetPayTransactionByOutTradeNumberResponse)> GetPayTransactionByOutTradeNumberAsync(PayTransactionByOutTradeNumberRequestDto requestModel)
        {
            var appId = "";
            var merchantId = "";
            var errMsg = "";
            //appId为null则默认获取配置第一个
            if (string.IsNullOrEmpty(requestModel.AppId))
                appId = _wechatPayOptions.Merchants?.FirstOrDefault().AppId;
            //商户号不指定，那么获取配置第一个
            if (string.IsNullOrEmpty(merchantId))
                merchantId = _wechatPayOptions.Merchants?.FirstOrDefault().MerchantId;
            var outTradeNumber = requestModel.OutTradeNumber;
            //创建一个http
            var client = _wechatTenpayHttpClientFactory.Create(merchantId);
            var request = new GetPayTransactionByOutTradeNumberRequest()
            {
                OutTradeNumber = outTradeNumber
            };
            var response = await client.ExecuteGetPayTransactionByOutTradeNumberAsync(request);
            if (!response.IsSuccessful())
            {
                _logger.LogWarning(
                    "JSAPI 商户订单查询失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                    response.RawStatus, response.ErrorCode, response.ErrorMessage
                );
                errMsg = response.ErrorMessage;
                return (errMsg, null);
            }
            else
                return (null, response);
        }
        #endregion

        #region 商户关闭订单
        /// <summary>
        /// 商户关闭订单(直接调微信接口关闭订单)
        /// </summary>
        /// <param name="requestModel"></param>
        /// <returns></returns>
        public async Task<(string, ClosePayTransactionResponse)> ClosePayTransactionByOutTradeNumberAsync(PayTransactionByOutTradeNumberRequestDto requestModel)
        {
            var appId = "";
            var merchantId = "";
            var errMsg = "";
            //appId为null则默认获取配置第一个
            if (string.IsNullOrEmpty(requestModel.AppId))
                appId = _wechatPayOptions.Merchants?.FirstOrDefault().AppId;
            //商户号不指定，那么获取配置第一个
            if (string.IsNullOrEmpty(merchantId))
                merchantId = _wechatPayOptions.Merchants?.FirstOrDefault().MerchantId;
            var outTradeNumber = requestModel.OutTradeNumber;
            //创建一个http
            var client = _wechatTenpayHttpClientFactory.Create(merchantId);
            var request = new ClosePayTransactionRequest()
            {
                OutTradeNumber = outTradeNumber
            };
            var response = await client.ExecuteClosePayTransactionAsync(request);
            if (!response.IsSuccessful())
            {
                _logger.LogWarning(
                    "JSAPI 关闭订单失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                    response.RawStatus, response.ErrorCode, response.ErrorMessage
                );
                errMsg = response.ErrorMessage;
                return (errMsg, null);
            }
            else
                return (null, response);
        }
        #endregion

        #region 微信支付回调通知
        /// <summary>
        /// 微信支付回调通知
        /// </summary>
        /// <param name="contentData"></param>
        /// <returns></returns>
        public async Task<string> AsynWechatNotify(string contentData)
        {
            try
            {
                //
            }
            catch (SystemException ex)
            {
            }
            return null;
        }
        #endregion

        #endregion

        #endregion
    }
    #endregion
}
